package com.fujimana.android.manacode.converter;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fujimana.android.manacode.converter.token.LinenoToken;
import com.fujimana.android.manacode.converter.token.LiteralToken;

public abstract class BaseConverter implements Converter {

	private Options options;
	
	private Map<String, Decorator> decorate;

	public BaseConverter(Options options) {
		if (options == null) {
			throw new IllegalArgumentException("options is null.");
		}

		this.options = options;
		this.decorate = new HashMap<String, Decorator>();
		
		this.decorate.put(LinenoToken.TYPE, LinenoToken.DECORATE);
		this.decorate.put(LiteralToken.TYPE, LiteralToken.DECORATE);
	}
	
	public Options getOptions() {
		return options;
	}
	
	@Override
	public String convert(Reader reader) throws IOException {
		StringWriter writer = new StringWriter();
		
		TokenParser parser = new TokenParser(getTokenMatchers(), getOptions());
		parser.parse(reader);
		
		List<Token> tokens = parser.getTokens();
		
		writer.append("<html><head></head><body><div style='"+ getFontsize(getOptions()) + "'>");
		for(Token token : tokens) {
			
			Decorator decorator = getDecorate(token);
			if(decorator != null && decorator.isDecorate(token.getValue())) {
				String startTag = "<span style='" + decorator.decorate() + "' >";
				String endTag = "</span>";
				writer.append(startTag + token.getFormatedValue() + endTag);
			} else {
				writer.append(token.getFormatedValue());
			}
			
		}
		
		writer.append("</div></body></html>");
		return writer.toString();
	}
	
	private String getFontsize(Options options) {
		return "font-size: " + options.getFontSize() + "px;";
	}

	@Override
	public String convert(String text) throws IOException {
		if (text == null) {
			text = "no source";
		}

		return convert(new StringReader(text));
	}

	@Override
	public String convert(InputStream stream) throws IOException {
		return convert(new InputStreamReader(stream, getOptions().getEncoding()));
	}

	public abstract List<TokenMatcher> getTokenMatchers();
	
	public Decorator getDecorate(Token token) {
		return this.decorate.get(token.getType());
	}
	
	protected Map<String, Decorator> getDecorate() {
		return decorate;
	}

	protected void setDecorate(Map<String, Decorator> decorate) {
		this.decorate = decorate;
	}
}
